home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / Main.bin / Container.java < prev    next >
Text File  |  1998-09-22  |  60KB  |  1,825 lines

  1. /*
  2.  * @(#)Container.java    1.147 98/09/04
  3.  *
  4.  * Copyright 1995-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  * 
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14. package java.awt;
  15.  
  16. import java.io.PrintStream;
  17. import java.io.PrintWriter;
  18. import java.awt.peer.ActiveEvent;
  19. import java.awt.peer.ContainerPeer;
  20. import java.awt.event.KeyEvent;
  21. import java.awt.event.MouseEvent;
  22. import java.awt.event.FocusEvent;
  23. import java.awt.event.ContainerEvent;
  24. import java.awt.event.ContainerListener;
  25. import java.io.ObjectOutputStream;
  26. import java.io.ObjectInputStream;
  27. import java.io.IOException;
  28.  
  29. /**
  30.  * A generic Abstract Window Toolkit(AWT) container object is a component 
  31.  * that can contain other AWT components.
  32.  * <p>
  33.  * Components added to a container are tracked in a list.  The order
  34.  * of the list will define the components' front-to-back stacking order 
  35.  * within the container.  If no index is specified when adding a
  36.  * component to a container, it will be added to the end of the list
  37.  * (and hence to the bottom of the stacking order).
  38.  * @version     1.147, 09/04/98
  39.  * @author     Arthur van Hoff
  40.  * @author     Sami Shaio
  41.  * @see       java.awt.Container#add(java.awt.Component, int)
  42.  * @see       java.awt.Container#getComponent(int)
  43.  * @see       java.awt.LayoutManager
  44.  * @since     JDK1.0
  45.  */
  46. public abstract class Container extends Component {
  47.  
  48.     /**
  49.      * The number of components in this container.
  50.      */
  51.     int ncomponents;
  52.  
  53.     /** 
  54.      * The components in this container.
  55.      */
  56.     Component component[] = new Component[4];
  57.  
  58.     /** 
  59.      * Layout manager for this container.
  60.      */
  61.     LayoutManager layoutMgr;
  62.  
  63.     /**
  64.      * Event router for lightweight components.  If this container
  65.      * is native, this dispatcher takes care of forwarding and 
  66.      * retargeting the events to lightweight components contained
  67.      * (if any).
  68.      */
  69.     private LightweightDispatcher dispatcher;
  70.  
  71.     /** Internal, cached size information */
  72.     private Dimension maxSize;
  73.  
  74.     transient ContainerListener containerListener;
  75.  
  76.     /*
  77.      * JDK 1.1 serialVersionUID 
  78.      */
  79.      private static final long serialVersionUID = 4613797578919906343L;  
  80.  
  81.     /**
  82.      * Constructs a new Container. Containers can be extended directly, 
  83.      * but are lightweight in this case and must be contained by a parent
  84.      * somewhere higher up in the component tree that is native.
  85.      * (such as Frame for example).
  86.      */
  87.     protected Container() {
  88.     }
  89.  
  90.     /** 
  91.      * Gets the number of components in this panel.
  92.      * @return    the number of components in this panel.
  93.      * @see       java.awt.Container#getComponent
  94.      * @since     JDK1.1
  95.      */
  96.     public int getComponentCount() {
  97.     return countComponents();
  98.     }
  99.  
  100.     /** 
  101.      * @deprecated As of JDK version 1.1,
  102.      * replaced by getComponentCount().
  103.      */
  104.     public int countComponents() {
  105.     return ncomponents;
  106.     }
  107.  
  108.     /** 
  109.      * Gets the nth component in this container.
  110.      * @param      n   the index of the component to get.
  111.      * @return     the n<sup>th</sup> component in this container.
  112.      * @exception  ArrayIndexOutOfBoundsException  
  113.      *                 if the n<sup>th</sup> value does not exist.     
  114.      * @since      JDK1.0
  115.      */
  116.     public Component getComponent(int n) {
  117.     synchronized (getTreeLock()) {
  118.         if ((n < 0) || (n >= ncomponents)) {
  119.         throw new ArrayIndexOutOfBoundsException("No such child: " + n);
  120.         }
  121.         return component[n];
  122.     }
  123.     }
  124.  
  125.     /**
  126.      * Gets all the components in this container.
  127.      * @return    an array of all the components in this container.     
  128.      * @since     JDK1.0
  129.      */
  130.     public Component[] getComponents() {
  131.     synchronized (getTreeLock()) {
  132.         Component list[] = new Component[ncomponents];
  133.         System.arraycopy(component, 0, list, 0, ncomponents);
  134.         return list;
  135.     }
  136.     }
  137.  
  138.     /**
  139.      * Determines the insets of this container, which indicate the size 
  140.      * of the container's border. 
  141.      * <p>
  142.      * A <code>Frame</code> object, for example, has a top inset that 
  143.      * corresponds to the height of the frame's title bar. 
  144.      * @return    the insets of this container.
  145.      * @see       java.awt.Insets
  146.      * @see       java.awt.LayoutManager
  147.      * @since     JDK1.1
  148.      */
  149.     public Insets getInsets() {
  150.         return insets();
  151.     }
  152.  
  153.     /**
  154.      * @deprecated As of JDK version 1.1,
  155.      * replaced by <code>getInsets()</code>.
  156.      */
  157.     public Insets insets() {
  158.     if (this.peer != null && this.peer instanceof ContainerPeer) {
  159.         ContainerPeer peer = (ContainerPeer)this.peer;
  160.         return peer.insets();
  161.     }
  162.     return new Insets(0, 0, 0, 0);
  163.     }
  164.  
  165.     /** 
  166.      * Adds the specified component to the end of this container. 
  167.      * @param     comp   the component to be added.
  168.      * @return    the component argument.     
  169.      * @since     JDK1.0
  170.      */
  171.     public Component add(Component comp) {
  172.         addImpl(comp, null, -1);
  173.     return comp;
  174.     }
  175.  
  176.     /**
  177.      * Adds the specified component to this container.
  178.      * It is strongly advised to use the 1.1 method, add(Component, Object),
  179.      * in place of this method.
  180.      */
  181.     public Component add(String name, Component comp) {
  182.     addImpl(comp, name, -1);
  183.     return comp;
  184.     }
  185.  
  186.     /** 
  187.      * Adds the specified component to this container at the given 
  188.      * position. 
  189.      * @param     comp   the component to be added.
  190.      * @param     index    the position at which to insert the component, 
  191.      *                   or <code>-1</code> to insert the component at the end.
  192.      * @return    the component <code>comp</code>
  193.      * @see      #remove
  194.      * @since     JDK1.0
  195.      */
  196.     public Component add(Component comp, int index) {
  197.     addImpl(comp, null, index);
  198.     return comp;
  199.     }
  200.  
  201.     /**
  202.      * Adds the specified component to the end of this container.
  203.      * Also notifies the layout manager to add the component to 
  204.      * this container's layout using the specified constraints object.
  205.      * @param     comp the component to be added
  206.      * @param     constraints an object expressing 
  207.      *                  layout contraints for this component
  208.      * @see       java.awt.LayoutManager
  209.      * @since     JDK1.1
  210.      */
  211.     public void add(Component comp, Object constraints) {
  212.     addImpl(comp, constraints, -1);
  213.     }
  214.  
  215.     /**
  216.      * Adds the specified component to this container with the specified
  217.      * constraints at the specified index.  Also notifies the layout 
  218.      * manager to add the component to the this container's layout using 
  219.      * the specified constraints object.
  220.      * @param comp the component to be added
  221.      * @param constraints an object expressing layout contraints for this
  222.      * @param index the position in the container's list at which to insert
  223.      * the component. -1 means insert at the end.
  224.      * component
  225.      * @see #remove
  226.      * @see LayoutManager
  227.      */
  228.     public void add(Component comp, Object constraints, int index) {
  229.        addImpl(comp, constraints, index);
  230.     }
  231.  
  232.     /**
  233.      * Adds the specified component to this container at the specified
  234.      * index. This method also notifies the layout manager to add 
  235.      * the component to this container's layout using the specified 
  236.      * constraints object.
  237.      * <p>
  238.      * This is the method to override if a program needs to track 
  239.      * every add request to a container. An overriding method should 
  240.      * usually include a call to the superclass's version of the method:
  241.      * <p>
  242.      * <blockquote>
  243.      * <code>super.addImpl(comp, constraints, index)</code>
  244.      * </blockquote>
  245.      * <p>
  246.      * @param     comp       the component to be added.
  247.      * @param     constraints an object expressing layout contraints 
  248.      *                 for this component.
  249.      * @param     index the position in the container's list at which to
  250.      *                 insert the component, where <code>-1</code> 
  251.      *                 means insert at the end.
  252.      * @see       java.awt.Container#add(java.awt.Component)       
  253.      * @see       java.awt.Container#add(java.awt.Component, int)       
  254.      * @see       java.awt.Container#add(java.awt.Component, java.lang.Object)       
  255.      * @see       java.awt.LayoutManager
  256.      * @since     JDK1.1
  257.      */
  258.     protected void addImpl(Component comp, Object constraints, int index) {
  259.     synchronized (getTreeLock()) {
  260.  
  261.         /* Check for correct arguments:  index in bounds,
  262.          * comp cannot be one of this container's parents,
  263.          * and comp cannot be a window.
  264.          */
  265.         if (index > ncomponents || (index < 0 && index != -1)) {
  266.         throw new IllegalArgumentException(
  267.               "illegal component position");
  268.         }
  269.         if (comp instanceof Container) {
  270.         for (Container cn = this; cn != null; cn=cn.parent) {
  271.             if (cn == comp) {
  272.             throw new IllegalArgumentException(
  273.                   "adding container's parent to itself");
  274.             }
  275.         }
  276.         }
  277.         if (comp instanceof Window) {
  278.             throw new IllegalArgumentException(
  279.                  "adding a window to a container");
  280.         }
  281.  
  282.         /* Reparent the component and tidy up the tree's state. */
  283.         if (comp.parent != null) {
  284.         comp.parent.remove(comp);
  285.         }
  286.  
  287.         /* Add component to list; allocate new array if necessary. */
  288.         if (ncomponents == component.length) {
  289.         Component newcomponents[] = new Component[ncomponents * 2];
  290.         System.arraycopy(component, 0, newcomponents, 0, ncomponents);
  291.         component = newcomponents;
  292.         }
  293.         if (index == -1 || index == ncomponents) {
  294.         component[ncomponents++] = comp;
  295.         } else {
  296.         System.arraycopy(component, index, component,
  297.                  index + 1, ncomponents - index);
  298.         component[index] = comp;
  299.         ncomponents++;
  300.         }
  301.         comp.parent = this;
  302.         if (valid) {
  303.         invalidate();
  304.         }
  305.         if (peer != null) {
  306.         comp.addNotify();
  307.         }
  308.         
  309.         /* Notify the layout manager of the added component. */
  310.         if (layoutMgr != null) {
  311.         if (layoutMgr instanceof LayoutManager2) {
  312.             ((LayoutManager2)layoutMgr).addLayoutComponent(comp, constraints);
  313.         } else if (constraints instanceof String) {
  314.             layoutMgr.addLayoutComponent((String)constraints, comp);
  315.         }
  316.         }
  317.             if (containerListener != null || 
  318.                 (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0) {
  319.                 ContainerEvent e = new ContainerEvent(this, 
  320.                                      ContainerEvent.COMPONENT_ADDED,
  321.                                      comp);
  322.                 processEvent(e);
  323.             }
  324.     }
  325.     }
  326.  
  327.     /** 
  328.      * Removes the component, specified by <code>index</code>, 
  329.      * from this container. 
  330.      * @param     index   the index of the component to be removed.
  331.      * @see #add
  332.      * @since JDK1.1
  333.      */
  334.     public void remove(int index) {
  335.     synchronized (getTreeLock()) {
  336.             Component comp = component[index];
  337.         if (peer != null) {
  338.         comp.removeNotify();
  339.         }
  340.         if (layoutMgr != null) {
  341.         layoutMgr.removeLayoutComponent(comp);
  342.         }
  343.         comp.parent = null;
  344.         System.arraycopy(component, index + 1,
  345.                  component, index,
  346.                  ncomponents - index - 1);
  347.         component[--ncomponents] = null;
  348.         if (valid) {
  349.         invalidate();
  350.         }
  351.             if (containerListener != null ||
  352.                 (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0) {
  353.                 ContainerEvent e = new ContainerEvent(this, 
  354.                                      ContainerEvent.COMPONENT_REMOVED,
  355.                                      comp);
  356.                 processEvent(e);
  357.             }
  358.         return;
  359.     }
  360.     }
  361.  
  362.     /** 
  363.      * Removes the specified component from this container.
  364.      * @param comp the component to be removed
  365.      * @see #add
  366.      * @since JDK1.0
  367.      */
  368.     public void remove(Component comp) {
  369.     synchronized (getTreeLock()) {
  370.         if (comp.parent == this)  {
  371.             /* Search backwards, expect that more recent additions
  372.          * are more likely to be removed.
  373.                  */
  374.                 Component component[] = this.component;
  375.         for (int i = ncomponents; --i >= 0; ) {
  376.             if (component[i] == comp) {
  377.                         remove(i);
  378.             }
  379.         }
  380.         }
  381.     }
  382.     }
  383.  
  384.     /** 
  385.      * Removes all the components from this container.
  386.      * @see #add
  387.      * @see #remove
  388.      * @since JDK1.0
  389.      */
  390.     public void removeAll() {
  391.     synchronized (getTreeLock()) {
  392.         while (ncomponents > 0) {
  393.         Component comp = component[--ncomponents];
  394.         component[ncomponents] = null;
  395.  
  396.         if (peer != null) {
  397.             comp.removeNotify();
  398.         }
  399.         if (layoutMgr != null) {
  400.             layoutMgr.removeLayoutComponent(comp);
  401.         }
  402.         comp.parent = null;
  403.                 if (containerListener != null ||
  404.                    (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0) {
  405.                     ContainerEvent e = new ContainerEvent(this, 
  406.                                      ContainerEvent.COMPONENT_REMOVED,
  407.                                      comp);
  408.                     processEvent(e);
  409.                 }
  410.         }
  411.         if (valid) {
  412.         invalidate();
  413.     }
  414.     }
  415.     }
  416.  
  417.     /** 
  418.      * Gets the layout manager for this container.  
  419.      * @see #doLayout
  420.      * @see #setLayout
  421.      * @since JDK1.0
  422.      */
  423.     public LayoutManager getLayout() {
  424.     return layoutMgr;
  425.     }
  426.  
  427.     /** 
  428.      * Sets the layout manager for this container.
  429.      * @param mgr the specified layout manager
  430.      * @see #doLayout
  431.      * @see #getLayout
  432.      * @since JDK1.0
  433.      */
  434.     public void setLayout(LayoutManager mgr) {
  435.     layoutMgr = mgr;
  436.     if (valid) {
  437.         invalidate();
  438.     }
  439.     }
  440.  
  441.     /** 
  442.      * Causes this container to lay out its components.  Most programs 
  443.      * should not call this method directly, but should invoke 
  444.      * the <code>validate</code> method instead.
  445.      * @see java.awt.LayoutManager#layoutContainer
  446.      * @see #setLayout
  447.      * @see #validate
  448.      * @since JDK1.1
  449.      */
  450.     public void doLayout() {
  451.     layout();
  452.     }
  453.  
  454.     /** 
  455.      * @deprecated As of JDK version 1.1,
  456.      * replaced by <code>doLayout()</code>.
  457.      */
  458.     public void layout() {
  459.     LayoutManager layoutMgr = this.layoutMgr;
  460.     if (layoutMgr != null) {
  461.         layoutMgr.layoutContainer(this);
  462.     }
  463.     }
  464.  
  465.     /** 
  466.      * Invalidates the container.  The container and all parents
  467.      * above it are marked as needing to be laid out.  This method can
  468.      * be called often, so it needs to execute quickly.
  469.      * @see #validate
  470.      * @see #layout
  471.      * @see LayoutManager
  472.      */
  473.     public void invalidate() {
  474.     if (layoutMgr instanceof LayoutManager2) {
  475.         LayoutManager2 lm = (LayoutManager2) layoutMgr;
  476.         lm.invalidateLayout(this);
  477.     }
  478.     super.invalidate();
  479.     }
  480.  
  481.     /** 
  482.      * Validates this container and all of its subcomponents.
  483.      * <p>
  484.      * AWT uses <code>validate</code> to cause a container to lay out   
  485.      * its subcomponents again after the components it contains
  486.      * have been added to or modified.
  487.      * @see #validate
  488.      * @see Component#invalidate
  489.      * @since JDK1.0
  490.      */
  491.     public void validate() {
  492.         /* Avoid grabbing lock unless really necessary. */
  493.     if (!valid) {
  494.         synchronized (getTreeLock()) {
  495.         if (!valid && peer != null) {
  496.                     Cursor oldCursor = getCursor();
  497.             ContainerPeer p = null;
  498.             if (peer instanceof ContainerPeer) {
  499.             p = (ContainerPeer) peer;
  500.             }
  501.             if (p != null) {
  502.             p.beginValidate();
  503.             }
  504.             validateTree();
  505.             valid = true;
  506.             if (p != null) {
  507.             p.endValidate();
  508.             }
  509.         }
  510.         }
  511.     }
  512.     }
  513.  
  514.     /**
  515.      * Recursively descends the container tree and recomputes the
  516.      * layout for any subtrees marked as needing it (those marked as
  517.      * invalid).  Synchronization should be provided by the method
  518.      * that calls this one:  <code>validate</code>.
  519.      */
  520.     protected void validateTree() {
  521.     if (!valid) {
  522.         doLayout();
  523.             Component component[] = this.component;
  524.         for (int i = 0 ; i < ncomponents ; ++i) {
  525.         Component comp = component[i];
  526.         if (   (comp instanceof Container) 
  527.                 && !(comp instanceof Window)
  528.             && !comp.valid) {
  529.             ((Container)comp).validateTree();
  530.         } else {
  531.             comp.validate();
  532.         }
  533.         }
  534.     }
  535.     valid = true;
  536.     }
  537.  
  538.     /** 
  539.      * Returns the preferred size of this container.  
  540.      * @return    an instance of <code>Dimension</code> that represents 
  541.      *                the preferred size of this container.
  542.      * @see       java.awt.Container#getMinimumSize       
  543.      * @see       java.awt.Container#getLayout
  544.      * @see       java.awt.LayoutManager#preferredLayoutSize(java.awt.Container)
  545.      * @see       java.awt.Component#getPreferredSize
  546.      * @since     JDK1.0
  547.      */
  548.     public Dimension getPreferredSize() {
  549.     return preferredSize();
  550.     }
  551.  
  552.     /** 
  553.      * @deprecated As of JDK version 1.1,
  554.      * replaced by <code>getPreferredSize()</code>.
  555.      */
  556.     public Dimension preferredSize() {
  557.     /* Avoid grabbing the lock if a reasonable cached size value
  558.      * is available.
  559.      */ 
  560.         Dimension dim = prefSize;
  561.         if (dim != null && isValid()) {
  562.         return dim;
  563.     }
  564.     synchronized (getTreeLock()) {
  565.         prefSize = (layoutMgr != null) ?
  566.                    layoutMgr.preferredLayoutSize(this) :
  567.                    super.preferredSize();
  568.         
  569.         return prefSize;
  570.     }
  571.     }
  572.  
  573.     /** 
  574.      * Returns the minimum size of this container.  
  575.      * @return    an instance of <code>Dimension</code> that represents 
  576.      *                the minimum size of this container.
  577.      * @see       java.awt.Container#getPreferredSize       
  578.      * @see       java.awt.Container#getLayout
  579.      * @see       java.awt.LayoutManager#minimumLayoutSize(java.awt.Container)
  580.      * @see       java.awt.Component#getMinimumSize
  581.      * @since     JDK1.1
  582.      */
  583.     public Dimension getMinimumSize() {
  584.     return minimumSize();
  585.     }
  586.  
  587.     /** 
  588.      * @deprecated As of JDK version 1.1,
  589.      * replaced by <code>getMinimumSize()</code>.
  590.      */
  591.     public Dimension minimumSize() {
  592.     /* Avoid grabbing the lock if a reasonable cached size value
  593.      * is available.
  594.      */ 
  595.         Dimension dim = minSize;
  596.         if (dim != null && isValid()) {
  597.         return dim;
  598.     }
  599.     synchronized (getTreeLock()) {
  600.         minSize = (layoutMgr != null) ?
  601.            layoutMgr.minimumLayoutSize(this) :
  602.            super.minimumSize();
  603.         return minSize;
  604.     }
  605.     }
  606.  
  607.     /** 
  608.      * Returns the maximum size of this container.  
  609.      * @see #getPreferredSize
  610.      */
  611.     public Dimension getMaximumSize() {
  612.     /* Avoid grabbing the lock if a reasonable cached size value
  613.      * is available.
  614.      */ 
  615.         Dimension dim = maxSize;
  616.         if (dim != null && isValid()) {
  617.         return dim;
  618.     }
  619.     if (layoutMgr instanceof LayoutManager2) {
  620.         synchronized (getTreeLock()) {
  621.         LayoutManager2 lm = (LayoutManager2) layoutMgr;
  622.         maxSize = lm.maximumLayoutSize(this);
  623.         }
  624.     } else {
  625.         maxSize = super.getMaximumSize();
  626.     }
  627.     return maxSize;
  628.     }
  629.  
  630.     /**
  631.      * Returns the alignment along the x axis.  This specifies how
  632.      * the component would like to be aligned relative to other 
  633.      * components.  The value should be a number between 0 and 1
  634.      * where 0 represents alignment along the origin, 1 is aligned
  635.      * the furthest away from the origin, 0.5 is centered, etc.
  636.      */
  637.     public float getAlignmentX() {
  638.     float xAlign;
  639.     if (layoutMgr instanceof LayoutManager2) {
  640.         synchronized (getTreeLock()) {
  641.         LayoutManager2 lm = (LayoutManager2) layoutMgr;
  642.         xAlign = lm.getLayoutAlignmentX(this);
  643.         }
  644.     } else {
  645.         xAlign = super.getAlignmentX();
  646.     }
  647.     return xAlign;
  648.     }
  649.  
  650.     /**
  651.      * Returns the alignment along the y axis.  This specifies how
  652.      * the component would like to be aligned relative to other 
  653.      * components.  The value should be a number between 0 and 1
  654.      * where 0 represents alignment along the origin, 1 is aligned
  655.      * the furthest away from the origin, 0.5 is centered, etc.
  656.      */
  657.     public float getAlignmentY() {
  658.     float yAlign;
  659.     if (layoutMgr instanceof LayoutManager2) {
  660.         synchronized (getTreeLock()) {
  661.         LayoutManager2 lm = (LayoutManager2) layoutMgr;
  662.         yAlign = lm.getLayoutAlignmentY(this);
  663.         }
  664.     } else {
  665.         yAlign = super.getAlignmentY();
  666.     }
  667.     return yAlign;
  668.     }
  669.  
  670.     /** 
  671.      * Paints the container.  This forwards the paint to any lightweight components 
  672.      * that are children of this container.  If this method is reimplemented, 
  673.      * super.paint(g) should be called so that lightweight components are properly
  674.      * rendered.  If a child component is entirely clipped by the current clipping
  675.      * setting in g, paint() will not be forwarded to that child.
  676.      *
  677.      * @param g the specified Graphics window
  678.      * @see   java.awt.Component#update(java.awt.Graphics)
  679.      */
  680.     public void paint(Graphics g) {
  681.     if (isShowing()) {
  682.         int ncomponents = this.ncomponents;
  683.             Component component[] = this.component;
  684.         Rectangle clip = g.getClipRect();
  685.         for (int i = ncomponents - 1 ; i >= 0 ; i--) {
  686.         Component comp = component[i];
  687.         if (comp != null && 
  688.             comp.peer instanceof java.awt.peer.LightweightPeer &&
  689.             comp.visible == true) {
  690.  
  691.             Rectangle cr = comp.getBounds();
  692.             if ((clip == null) || cr.intersects(clip)) {
  693.             Graphics cg = g.create(cr.x, cr.y, cr.width, cr.height);
  694.             cg.setFont(comp.getFont());
  695.             try {
  696.                 comp.paint(cg);
  697.             } finally {
  698.                 cg.dispose();
  699.             }
  700.             }
  701.         }
  702.         }
  703.     }
  704.     }
  705.  
  706.     /** 
  707.      * Updates the container.  This forwards the update to any lightweight components 
  708.      * that are children of this container.  If this method is reimplemented, 
  709.      * super.update(g) should be called so that lightweight components are properly
  710.      * rendered.  If a child component is entirely clipped by the current clipping
  711.      * setting in g, update() will not be forwarded to that child.
  712.      *
  713.      * @param g the specified Graphics window
  714.      * @see   java.awt.Component#update(java.awt.Graphics)
  715.      */
  716.     public void update(Graphics g) {
  717.         if (isShowing()) {
  718.             if (! (peer instanceof java.awt.peer.LightweightPeer)) {
  719.                 g.setColor(getBackground());
  720.                 g.fillRect(0, 0, width, height);
  721.                 g.setColor(getForeground());
  722.             }
  723.             super.update(g);
  724.         }
  725.     }
  726.  
  727.     /** 
  728.      * Prints the container.  This forwards the print to any lightweight components 
  729.      * that are children of this container.  If this method is reimplemented, 
  730.      * super.print(g) should be called so that lightweight components are properly
  731.      * rendered.  If a child component is entirely clipped by the current clipping
  732.      * setting in g, print() will not be forwarded to that child.
  733.      *
  734.      * @param g the specified Graphics window
  735.      * @see   java.awt.Component#update(java.awt.Graphics)
  736.      */
  737.     public void print(Graphics g) {
  738.         super.print(g);  // By default, Component.print() calls paint()
  739.  
  740.         int ncomponents = this.ncomponents;
  741.         Component component[] = this.component;
  742.         Rectangle clip = g.getClipRect();
  743.     for (int i = ncomponents - 1 ; i >= 0 ; i--) {
  744.         Component comp = component[i];
  745.         if (comp != null && 
  746.             comp.peer instanceof java.awt.peer.LightweightPeer ) {
  747.         Rectangle cr = comp.getBounds();
  748.         if ((clip==null) || cr.intersects(clip)) {
  749.             Graphics cg = g.create(cr.x, cr.y, cr.width, cr.height);
  750.             cg.setFont(comp.getFont());
  751.             try {
  752.             comp.print(cg);
  753.             } finally {
  754.             cg.dispose();
  755.             }
  756.         }
  757.             }
  758.         }
  759.     }
  760.  
  761.     /** 
  762.      * Paints each of the components in this container. 
  763.      * @param     g   the graphics context.
  764.      * @see       java.awt.Component#paint
  765.      * @see       java.awt.Component#paintAll
  766.      * @since     JDK1.0
  767.      */
  768.     public void paintComponents(Graphics g) {
  769.         int ncomponents = this.ncomponents;
  770.         Component component[] = this.component;
  771.     for (int i = ncomponents - 1 ; i >= 0 ; i--) {
  772.         Component comp = component[i];
  773.         if (comp != null) {
  774.                 Graphics cg = comp.getGraphics();
  775.                 Rectangle parentRect = g.getClipRect();
  776.  
  777.                 // Calculate the clipping region of the child's graphics
  778.                 // context, by taking the intersection of the parent's
  779.                 // clipRect (if any) and the child's bounds, and then 
  780.                 // translating it's coordinates to be relative to the child.
  781.                 if (parentRect != null) {
  782.                     Rectangle childRect = comp.getBounds();
  783.                     if (childRect.intersects(parentRect) == false) {
  784.                         // Child component is completely clipped out: ignore.
  785.                         continue;
  786.                     }
  787.                     Rectangle childClipRect = 
  788.                         childRect.intersection(parentRect);
  789.                     childClipRect.translate(-childRect.x, -childRect.y);
  790.                     cg.clipRect(childClipRect.x, childClipRect.y,
  791.                                 childClipRect.width, childClipRect.height);
  792.                 }
  793.  
  794.         try {
  795.             comp.paintAll(cg);
  796.         } finally {
  797.             cg.dispose();
  798.         }
  799.         }
  800.     }
  801.     }
  802.  
  803.     /** 
  804.      * Prints each of the components in this container. 
  805.      * @param     g   the graphics context.
  806.      * @see       java.awt.Component#print
  807.      * @see       java.awt.Component#printAll
  808.      * @since     JDK1.0
  809.      */
  810.     public void printComponents(Graphics g) {
  811.         int ncomponents = this.ncomponents;
  812.         Component component[] = this.component;
  813.  
  814.     // A seriously sad hack--
  815.     // Lightweight components always paint behind peered components,
  816.     // even if they are at the top of the Z order. We emulate this
  817.     // behavior by making two printing passes: the first for lightweights;
  818.     // the second for heavyweights.
  819.  
  820.         for (int i = ncomponents - 1 ; i >= 0 ; i--) {
  821.             Component comp = component[i];
  822.             if (comp != null && 
  823.             comp.peer instanceof java.awt.peer.LightweightPeer) {
  824.             printOneComponent(g, comp);
  825.             }
  826.         }
  827.         for (int i = ncomponents - 1 ; i >= 0 ; i--) {
  828.             Component comp = component[i];
  829.             if (comp != null && 
  830.             !(comp.peer instanceof java.awt.peer.LightweightPeer)) {
  831.             printOneComponent(g, comp);
  832.             }
  833.         }
  834.     }
  835.  
  836.     private void printOneComponent(Graphics g, Component comp) {
  837.         Graphics cg = g.create(comp.x, comp.y, comp.width,
  838.                    comp.height);
  839.     cg.setFont(comp.getFont());
  840.     try {
  841.         comp.printAll(cg);
  842.     } finally {
  843.         cg.dispose();
  844.     }
  845.     }
  846.  
  847.     /**
  848.      * Simulates the peer callbacks into java.awt for printing of
  849.      * lightweight Containers.
  850.      * @param     g   the graphics context to use for printing.
  851.      * @see       Component#printAll
  852.      * @see       #printComponents
  853.      */
  854.     void lightweightPrint(Graphics g) {
  855.         super.lightweightPrint(g);
  856.         printComponents(g);
  857.     }
  858.  
  859.     /**
  860.      * Adds the specified container listener to receive container events
  861.      * from this container.
  862.      * @param l the container listener
  863.      */ 
  864.     public synchronized void addContainerListener(ContainerListener l) {
  865.     containerListener = AWTEventMulticaster.add(containerListener, l);
  866.         newEventsOnly = true;    
  867.     }
  868.  
  869.     /**
  870.      * Removes the specified container listener so it no longer receives
  871.      * container events from this container.
  872.      * @param l the container listener
  873.      */ 
  874.     public synchronized void removeContainerListener(ContainerListener l) {
  875.     containerListener = AWTEventMulticaster.remove(containerListener, l);
  876.     }
  877.  
  878.     // REMIND: remove when filtering is done at lower level
  879.     boolean eventEnabled(AWTEvent e) {
  880.         int id = e.getID();
  881.  
  882.         if (id == ContainerEvent.COMPONENT_ADDED ||
  883.             id == ContainerEvent.COMPONENT_REMOVED) {
  884.             if ((eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
  885.                 containerListener != null) {
  886.                 return true;
  887.             }
  888.             return false;
  889.         }
  890.         return super.eventEnabled(e);
  891.     }          
  892.  
  893.     /**
  894.      * Processes events on this container. If the event is a ContainerEvent,
  895.      * it invokes the processContainerEvent method, else it invokes its
  896.      * superclass's processEvent.
  897.      * @param e the event
  898.      */
  899.     protected void processEvent(AWTEvent e) {
  900.         if (e instanceof ContainerEvent) {
  901.             processContainerEvent((ContainerEvent)e);     
  902.             return;
  903.         }
  904.     super.processEvent(e);
  905.     }
  906.  
  907.     /** 
  908.      * Processes container events occurring on this container by
  909.      * dispatching them to any registered ContainerListener objects.
  910.      * NOTE: This method will not be called unless container events
  911.      * are enabled for this component; this happens when one of the
  912.      * following occurs:
  913.      * a) A ContainerListener object is registered via addContainerListener()
  914.      * b) Container events are enabled via enableEvents()
  915.      * @see Component#enableEvents
  916.      * @param e the container event
  917.      */  
  918.     protected void processContainerEvent(ContainerEvent e) {
  919.         if (containerListener != null) {
  920.             switch(e.getID()) {
  921.               case ContainerEvent.COMPONENT_ADDED:
  922.                 containerListener.componentAdded(e);
  923.                 break;
  924.               case ContainerEvent.COMPONENT_REMOVED:
  925.                 containerListener.componentRemoved(e);
  926.                 break;
  927.             }
  928.         }
  929.     }
  930.  
  931.     /*
  932.      * Dispatches an event to this component or one of its sub components.
  933.      * @param e the event
  934.      */
  935.     void dispatchEventImpl(AWTEvent e) {
  936.     if ((dispatcher != null) && dispatcher.dispatchEvent(e)) {
  937.         // event was sent to a lightweight component.  The
  938.         // native-produced event sent to the native container
  939.         // must be properly disposed of by the peer, so it 
  940.         // gets forwarded.  If the native host has been removed
  941.         // as a result of the sending the lightweight event, 
  942.         // the peer reference will be null.
  943.         e.consume();
  944.         if (peer != null) {
  945.         peer.handleEvent(e);
  946.         }
  947.         return;
  948.     }
  949.     super.dispatchEventImpl(e);
  950.     }
  951.  
  952.     /*
  953.      * Dispatches an event to this component, without trying to forward
  954.      * it to any sub components
  955.      * @param e the event
  956.      */
  957.     void dispatchEventToSelf(AWTEvent e) {
  958.     super.dispatchEventImpl(e);
  959.     }
  960.  
  961.     /**
  962.      * Fetchs the top-most (deepest) lightweight component that is interested
  963.      * in receiving mouse events.
  964.      */
  965.     Component getMouseEventTarget(int x, int y, boolean includeSelf) {
  966.     int ncomponents = this.ncomponents;
  967.         Component component[] = this.component;
  968.     for (int i = 0 ; i < ncomponents ; i++) {
  969.         Component comp = component[i];
  970.         if ((comp != null) && (comp.contains(x - comp.x, y - comp.y)) &&
  971.         (comp.peer instanceof java.awt.peer.LightweightPeer) &&
  972.         (comp.visible == true)) {
  973.         // found a component that intersects the point, see if there is 
  974.         // a deeper possibility.
  975.         if (comp instanceof Container) {
  976.             Container child = (Container) comp;
  977.             Component deeper = child.getMouseEventTarget(x - child.x, y - child.y, includeSelf);
  978.             if (deeper != null) {
  979.             return deeper;
  980.             }
  981.         } else {
  982.             if ((comp.mouseListener != null) || 
  983.             ((comp.eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0) ||
  984.             (comp.mouseMotionListener != null) ||
  985.             ((comp.eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0)) {
  986.             // there isn't a deeper target, but this component is a target
  987.             return comp;
  988.             }
  989.         }
  990.         }
  991.     }
  992.     
  993.     boolean isPeerOK;
  994.     boolean    isMouseOverMe;
  995.     boolean    isMouseListener;
  996.     boolean    isMotionListener;
  997.     
  998.     isPeerOK = (peer instanceof java.awt.peer.LightweightPeer) || includeSelf;
  999.     isMouseOverMe = contains(x,y);
  1000.     isMouseListener = (mouseListener != null) ||
  1001.               ((eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0);
  1002.     isMotionListener = (mouseMotionListener != null) ||
  1003.                ((eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0);
  1004.  
  1005.     // didn't find a child target, return this component if it's a possible target
  1006.     if ( isMouseOverMe && isPeerOK && (isMouseListener || isMotionListener) ) {
  1007.         return this;
  1008.     }
  1009.     // no possible target
  1010.     return null;
  1011.     }
  1012.  
  1013.     /**
  1014.      * This is called by lightweight components that want the containing
  1015.      * windowed parent to enable some kind of events on their behalf.
  1016.      * This is needed for events that are normally only dispatched to 
  1017.      * windows to be accepted so that they can be forwarded downward to 
  1018.      * the lightweight component that has enabled them.
  1019.      */
  1020.     void proxyEnableEvents(long events) {
  1021.     if (peer instanceof java.awt.peer.LightweightPeer) {
  1022.         // this container is lightweight.... continue sending it
  1023.         // upward.
  1024.         parent.proxyEnableEvents(events);
  1025.     } else {
  1026.         // This is a native container, so it needs to host
  1027.         // one of it's children.  If this function is called before
  1028.         // a peer has been created we don't yet have a dispatcher
  1029.         // because it has not yet been determined if this instance
  1030.         // is lightweight.
  1031.         if (dispatcher != null) {
  1032.         dispatcher.enableEvents(events);
  1033.         }
  1034.     }
  1035.     }
  1036.  
  1037.     Window getWindow() {
  1038.         Container w = this;
  1039.         while(!(w instanceof Window)) {
  1040.             w = w.getParent();
  1041.         }
  1042.         return (Window)w;
  1043.     }
  1044.  
  1045.     /**
  1046.      * This is called by lightweight components that have requested focus.
  1047.      * The focus request is propagated upward until a native container is
  1048.      * found, at which point the native container requests focus and records
  1049.      * the component the host is requesting focus for.
  1050.      */
  1051.     void proxyRequestFocus(Component c) {
  1052.     if (peer instanceof java.awt.peer.LightweightPeer) {
  1053.         // this container is lightweight... continue sending it
  1054.         // upward.
  1055.         parent.proxyRequestFocus(c);
  1056.     } else {
  1057.         // This is a windowed container, so record true focus
  1058.         // component and request focus from the native window
  1059.         // if needed.
  1060.         if (dispatcher.setFocusRequest(c)) {
  1061.                 // If the focus is currently somewhere within this Window,
  1062.                 // call the peer to set focus to this Container.  This way,
  1063.                 // we avoid activating this Window if it's not currently
  1064.                 // active.  -fredx, 2-19-98, bug #4111098
  1065.                 if ( isContainingWindowActivated() ) {
  1066.         // NOTE: See bug #4133261-- we should look into removing this fix
  1067.         // or at least make hw and lw components behave the same 
  1068.         // -robi 7-30-98
  1069.             requestFocus();
  1070.         }
  1071.         }
  1072.     }
  1073.     }
  1074.  
  1075.     /*
  1076.      * Determines if the top-level window containing 
  1077.      * this component is activated
  1078.      */
  1079.     private boolean isContainingWindowActivated() {
  1080.     Component comp = this;
  1081.     while ( !(comp instanceof Window) ) {
  1082.         comp = comp.getParent();
  1083.     }
  1084.     return ((Window)comp).isActive();
  1085.     }
  1086.  
  1087.     /**
  1088.      * @deprecated As of JDK version 1.1,
  1089.      * replaced by <code>dispatchEvent(AWTEvent e)</code>
  1090.      */
  1091.     public void deliverEvent(Event e) {
  1092.     Component comp = getComponentAt(e.x, e.y);
  1093.     if ((comp != null) && (comp != this)) {
  1094.         e.translate(-comp.x, -comp.y);
  1095.         comp.deliverEvent(e);
  1096.     } else {
  1097.         postEvent(e);
  1098.     }
  1099.     }
  1100.  
  1101.     /**
  1102.      * Locates the component that contains the x,y position.  The
  1103.      * top-most child component is returned in the case where there
  1104.      * is overlap in the components.  This is determined by finding
  1105.      * the component closest to the index 0 that claims to contain
  1106.      * the given point via Component.contains().
  1107.      * @param x the <i>x</i> coordinate
  1108.      * @param y the <i>y</i> coordinate
  1109.      * @return null if the component does not contain the position.
  1110.      * If there is no child component at the requested point and the 
  1111.      * point is within the bounds of the container the container itself 
  1112.      * is returned; otherwise the top-most child is returned.
  1113.      * @see Component#contains
  1114.      * @since JDK1.1
  1115.      */
  1116.     public Component getComponentAt(int x, int y) {
  1117.     return locate(x, y);
  1118.     }
  1119.  
  1120.     /**
  1121.      * @deprecated As of JDK version 1.1,
  1122.      * replaced by <code>getComponentAt(int, int)</code>.
  1123.      */
  1124.     public Component locate(int x, int y) {
  1125.     if (!contains(x, y)) {
  1126.         return null;
  1127.     }
  1128.     int ncomponents = this.ncomponents;
  1129.         Component component[] = this.component;
  1130.     for (int i = 0 ; i < ncomponents ; i++) {
  1131.         Component comp = component[i];
  1132.         if (comp != null) {
  1133.         if (comp.contains(x - comp.x, y - comp.y)) {
  1134.             return comp;
  1135.         }
  1136.         }
  1137.     }
  1138.     return this;
  1139.     }
  1140.  
  1141.     /**
  1142.      * Gets the component that contains the specified point.
  1143.      * @param      p   the point.
  1144.      * @return     returns the component that contains the point,
  1145.      *                 or <code>null</code> if the component does 
  1146.      *                 not contain the point. 
  1147.      * @see        java.awt.Component#contains 
  1148.      * @since      JDK1.1 
  1149.      */
  1150.     public Component getComponentAt(Point p) {
  1151.     return getComponentAt(p.x, p.y);
  1152.     }
  1153.  
  1154.     /** 
  1155.      * Notifies the container to create a peer. It will also
  1156.      * notify the components contained in this container.
  1157.      * This method should be called by <code>Container.add</code>, 
  1158.      * and not by user code directly.
  1159.      * @see #removeNotify
  1160.      * @since JDK1.0
  1161.      */
  1162.     public void addNotify() {
  1163.         synchronized (getTreeLock()) {
  1164.         // addNotify() on the children may cause proxy event enabling
  1165.         // on this instance, so we first call super.addNotify() and
  1166.         // possibly create an lightweight event dispatcher before calling
  1167.         // addNotify() on the children which may be lightweight.
  1168.         super.addNotify();
  1169.         if (! (peer instanceof java.awt.peer.LightweightPeer)) {
  1170.             dispatcher = new LightweightDispatcher(this);
  1171.         }
  1172.         int ncomponents = this.ncomponents;
  1173.             Component component[] = this.component;
  1174.         for (int i = 0 ; i < ncomponents ; i++) {
  1175.             component[i].addNotify();
  1176.          }
  1177.         }
  1178.     }
  1179.  
  1180.     /** 
  1181.      * Notifies this container and all of its subcomponents to remove 
  1182.      * their peers. 
  1183.      * This method should be invoked by the container's 
  1184.      * <code>remove</code> method, and not directly by user code.
  1185.      * @see       java.awt.Container#remove(int)
  1186.      * @see       java.awt.Container#remove(java.awt.Component)
  1187.      * @since     JDK1.0
  1188.      */
  1189.     public void removeNotify() {
  1190.         synchronized(getTreeLock()) {
  1191.             int ncomponents = this.ncomponents;
  1192.             Component component[] = this.component;
  1193.         for (int i = 0 ; i < ncomponents ; i++) {
  1194.             component[i].removeNotify();
  1195.         }
  1196.         super.removeNotify();
  1197.         }
  1198.     }
  1199.  
  1200.     /**
  1201.      * Checks if the component is contained in the component hierarchy of
  1202.      * this container.
  1203.      * @param c the component
  1204.      * @return     <code>true</code> if it is an ancestor; 
  1205.      *             <code>true</code> otherwise.
  1206.      * @since      JDK1.1
  1207.      */
  1208.     public boolean isAncestorOf(Component c) {
  1209.     Container p;
  1210.     if (c == null || ((p = c.getParent()) == null)) {
  1211.         return false;
  1212.     }
  1213.     while (p != null) {
  1214.         if (p == this) {
  1215.         return true;
  1216.         }
  1217.         p = p.getParent();
  1218.     }
  1219.     return false;
  1220.     }
  1221.  
  1222.     /**
  1223.      * Returns the parameter string representing the state of this 
  1224.      * container. This string is useful for debugging. 
  1225.      * @return    the parameter string of this container.
  1226.      * @since     JDK1.0
  1227.      */
  1228.     protected String paramString() {
  1229.     String str = super.paramString();
  1230.     LayoutManager layoutMgr = this.layoutMgr;
  1231.     if (layoutMgr != null) {
  1232.         str += ",layout=" + layoutMgr.getClass().getName();
  1233.     }
  1234.     return str;
  1235.     }
  1236.  
  1237.     /**
  1238.      * Prints a listing of this container to the specified output 
  1239.      * stream. The listing starts at the specified indentation. 
  1240.      * @param    out      a print stream.
  1241.      * @param    indent   the number of spaces to indent.
  1242.      * @see      java.awt.Component#list(java.io.PrintStream, int)
  1243.      * @since    JDK
  1244.      */
  1245.     public void list(PrintStream out, int indent) {
  1246.     super.list(out, indent);
  1247.     int ncomponents = this.ncomponents;
  1248.         Component component[] = this.component;
  1249.     for (int i = 0 ; i < ncomponents ; i++) {
  1250.         Component comp = component[i];
  1251.         if (comp != null) {
  1252.         comp.list(out, indent+1);
  1253.         }
  1254.     }
  1255.     }
  1256.  
  1257.     /**
  1258.      * Prints out a list, starting at the specified indention, to the specified
  1259.      * print writer.
  1260.      */
  1261.     public void list(PrintWriter out, int indent) {
  1262.     super.list(out, indent);
  1263.     int ncomponents = this.ncomponents;
  1264.         Component component[] = this.component;
  1265.     for (int i = 0 ; i < ncomponents ; i++) {
  1266.         Component comp = component[i];
  1267.         if (comp != null) {
  1268.         comp.list(out, indent+1);
  1269.         }
  1270.     }
  1271.     }
  1272.  
  1273.     void setFocusOwner(Component c) {
  1274.     Container parent = this.parent;
  1275.     if (parent != null) {
  1276.         parent.setFocusOwner(c);
  1277.     }
  1278.     }
  1279.  
  1280.     void preProcessKeyEvent(KeyEvent e) {
  1281.         Container parent = this.parent;
  1282.         if (parent != null) {
  1283.             parent.preProcessKeyEvent(e);
  1284.         }
  1285.     }
  1286.  
  1287.     void postProcessKeyEvent(KeyEvent e) {
  1288.         Container parent = this.parent;
  1289.         if (parent != null) {
  1290.             parent.postProcessKeyEvent(e);
  1291.         }
  1292.     }
  1293.  
  1294.     void transferFocus(Component base) {
  1295.     nextFocus(base);
  1296.     }
  1297.  
  1298.     boolean postsOldMouseEvents() {
  1299.         return true;
  1300.     }
  1301.  
  1302.     /**
  1303.      * @deprecated As of JDK version 1.1,
  1304.      * replaced by transferFocus(Component).
  1305.      */
  1306.     void nextFocus(Component base) {
  1307.     Container parent = this.parent;
  1308.     if (parent != null) {
  1309.         parent.transferFocus(base);
  1310.     }
  1311.     }
  1312.  
  1313.     /* Serialization support.  A Container is responsible for
  1314.      * restoring the parent fields of its component children. 
  1315.      */
  1316.  
  1317.     private int containerSerializedDataVersion = 1;
  1318.  
  1319.  
  1320.     private void writeObject(ObjectOutputStream s)
  1321.       throws IOException 
  1322.     {
  1323.       s.defaultWriteObject();
  1324.  
  1325.       AWTEventMulticaster.save(s, containerListenerK, containerListener);
  1326.       s.writeObject(null);
  1327.     }
  1328.  
  1329.  
  1330.     private void readObject(ObjectInputStream s)
  1331.       throws ClassNotFoundException, IOException 
  1332.     {
  1333.       s.defaultReadObject();
  1334.  
  1335.       Component component[] = this.component;
  1336.       for(int i = 0; i < ncomponents; i++)
  1337.     component[i].parent = this;
  1338.  
  1339.       Object keyOrNull;
  1340.       while(null != (keyOrNull = s.readObject())) {
  1341.     String key = ((String)keyOrNull).intern();
  1342.  
  1343.     if (containerListenerK == key) 
  1344.       addContainerListener((ContainerListener)(s.readObject()));
  1345.  
  1346.     else // skip value for unrecognized key
  1347.       s.readObject();
  1348.       }
  1349.     }
  1350. }
  1351.  
  1352.  
  1353. /**
  1354.  * Class to manage the dispatching of events to the lightweight
  1355.  * components contained by a native container.
  1356.  * 
  1357.  * @author Timothy Prinzing
  1358.  */
  1359. class LightweightDispatcher implements java.io.Serializable,
  1360.                     EventQueueListener {
  1361.  
  1362.     /*
  1363.      * JDK 1.1 serialVersionUID 
  1364.      */
  1365.     private static final long serialVersionUID = 5184291520170872969L;
  1366.     /*
  1367.      * Our own mouse event for when we're dragged over from another hw container
  1368.      */
  1369.     private static final int  LWD_MOUSE_DRAGGED_OVER = AWTEvent.RESERVED_ID_MAX + 1;
  1370.  
  1371.     LightweightDispatcher(Container nativeContainer) {
  1372.     this.nativeContainer = nativeContainer;
  1373.     focus = null;
  1374.     mouseEventTarget = null;
  1375.     eventMask = 0;
  1376.     }
  1377.  
  1378.     /**
  1379.      * Enables events to lightweight components.
  1380.      */
  1381.     void enableEvents(long events) {
  1382.     eventMask |= events;
  1383.     }
  1384.  
  1385.     /**
  1386.      * This is called by the hosting native container on behalf of lightweight 
  1387.      * components that have requested focus.  The focus request is propagated 
  1388.      * upward from the requesting lightweight component until a windowed host 
  1389.      * is found, at which point the windowed host calls this method.  This method 
  1390.      * returns whether or not the peer associated with the native component needs 
  1391.      * to request focus from the native window system. 
  1392.      *
  1393.      * If a lightweight component already has focus the focus events are synthesized 
  1394.      * since there will be no native events to drive the focus.  If the native host 
  1395.      * already has focus, the focus gained is synthesized for the lightweight component 
  1396.      * requesting focus since it will receive no native focus requests.
  1397.      */
  1398.     boolean setFocusRequest(Component c) {
  1399.     boolean peerNeedsRequest = true;
  1400.     Window w = nativeContainer.getWindow();
  1401.     if ((w != null) && (c != null)) {
  1402.         Component focusOwner = w.getFocusOwner();
  1403.         if (focusOwner == null) {
  1404.  
  1405.         // No focus in this component
  1406.         focus = c;
  1407.  
  1408.         } else if (focusOwner == nativeContainer) {
  1409.         // This container already has focus, so just 
  1410.         // send FOCUS_GAINED event to lightweight component
  1411.         focus = c ;
  1412.         c.dispatchEvent(new FocusEvent(c, FocusEvent.FOCUS_GAINED, false));
  1413.         peerNeedsRequest = false;
  1414.         } else if (focusOwner == c) {
  1415.         // lightweight already has the focus
  1416.         focus = c ;
  1417.         peerNeedsRequest = false;
  1418.         } else if (focusOwner == focus) {
  1419.         // a lightweight component has focus currently and a new one has been
  1420.         // requested.  There won't be any window-system events associated with
  1421.         // this so we go ahead and send FOCUS_LOST for the old and FOCUS_GAINED
  1422.         // for the new.
  1423.         if (focus != null) {
  1424.             focus.dispatchEvent(new FocusEvent(focus, 
  1425.                                FocusEvent.FOCUS_LOST, 
  1426.                                false));
  1427.                 }
  1428.         focus = c ;
  1429.         c.dispatchEvent(new FocusEvent(c, FocusEvent.FOCUS_GAINED, false));
  1430.         peerNeedsRequest = false;
  1431.         }else { 
  1432.         //Fix for bug 4095214
  1433.         //Paul Sheehan
  1434.                 focus = c ; 
  1435.             } 
  1436.        }
  1437.     return peerNeedsRequest;
  1438.     } // setFocusRequest()
  1439.  
  1440.     /**
  1441.      * Dispatches an event to a lightweight sub-component if necessary, and
  1442.      * returns whether or not the event was forwarded to a lightweight
  1443.      * sub-component.
  1444.      *
  1445.      * @param e the event
  1446.      */
  1447.     boolean dispatchEvent(AWTEvent e) {
  1448.     if ((eventMask & PROXY_EVENT_MASK) != 0) {
  1449.         if ((e instanceof MouseEvent) && 
  1450.         ((eventMask & MOUSE_MASK) != 0)) {
  1451.         
  1452.         MouseEvent me = (MouseEvent) e;
  1453.         return processMouseEvent(me);
  1454.  
  1455.         } else if (e instanceof FocusEvent) {
  1456.         
  1457.         FocusEvent fe = (FocusEvent) e;
  1458.         return processFocusEvent(fe);
  1459.  
  1460.         } else if (e instanceof KeyEvent) {
  1461.  
  1462.         KeyEvent ke = (KeyEvent) e;
  1463.         return processKeyEvent(ke);
  1464.  
  1465.         }
  1466.     }
  1467.     return false;
  1468.     }
  1469.  
  1470.     private boolean processKeyEvent(KeyEvent e) {
  1471.     if (focus != null) {
  1472.         // Don't duplicate the event here.
  1473.         // The KeyEvent for LightWeightComponent is also passed to 
  1474.         // input methods and their native handlers. The native handlers
  1475.         // require the original native event data to be attached to
  1476.         // the KeyEvent.
  1477.         Component source = e.getComponent();
  1478.         e.setSource(focus);
  1479.         focus.dispatchEvent(e);
  1480.         e.setSource(source);
  1481.         return e.isConsumed();
  1482.     }
  1483.     return false;
  1484.     }
  1485.     
  1486.     private boolean processFocusEvent(FocusEvent e) {
  1487.     if (focus != null) {
  1488.         int id = e.getID();
  1489.         FocusEvent retargeted = new FocusEvent(focus, id, e.isTemporary());
  1490.         focus.dispatchEvent(retargeted);
  1491.         if ((id == FocusEvent.FOCUS_LOST) && (e.isTemporary() == false)) {
  1492.         focus = null;
  1493.         }
  1494.         return true;
  1495.     }
  1496.     return false;
  1497.     }
  1498.  
  1499.     /**
  1500.      * This method attempts to distribute a mouse event to a lightweight
  1501.      * component.  It tries to avoid doing any unnecessary probes down
  1502.      * into the component tree to minimize the overhead of determining
  1503.      * where to route the event, since mouse movement events tend to
  1504.      * come in large and frequent amounts.
  1505.      */
  1506.     private boolean processMouseEvent(MouseEvent e) {
  1507.     int id = e.getID();
  1508.     Component targetOver;
  1509.     Component lwOver;
  1510.  
  1511.     targetOver = nativeContainer.getMouseEventTarget(e.getX(), e.getY(),true);
  1512.     trackMouseEnterExit(targetOver, e);
  1513.  
  1514.     if (mouseEventTarget == null) {
  1515.         if ( id == MouseEvent.MOUSE_MOVED ||
  1516.              id == MouseEvent.MOUSE_PRESSED ) {
  1517.         lwOver = (targetOver != nativeContainer) ? targetOver : null;
  1518.         setMouseTarget(lwOver,e);
  1519.         }
  1520.     }
  1521.  
  1522.     if (mouseEventTarget != null) {
  1523.         // we are currently forwarding to some component, check
  1524.         // to see if we should continue to forward.
  1525.         switch(id) {
  1526.         case MouseEvent.MOUSE_DRAGGED:
  1527.         if(dragging) {
  1528.             retargetMouseEvent(mouseEventTarget, id, e);
  1529.         }
  1530.         break;
  1531.         case MouseEvent.MOUSE_PRESSED:
  1532.         dragging = true;
  1533.         retargetMouseEvent(mouseEventTarget, id, e);
  1534.         break;
  1535.         case MouseEvent.MOUSE_RELEASED:
  1536.         dragging = false;
  1537.         retargetMouseEvent(mouseEventTarget, id, e);
  1538.         lwOver = nativeContainer.getMouseEventTarget(e.getX(), e.getY(),false);
  1539.         setMouseTarget(lwOver, e);
  1540.         break;
  1541.         case MouseEvent.MOUSE_CLICKED:
  1542.         retargetMouseEvent(mouseEventTarget, id, e);
  1543.         break;
  1544.         case MouseEvent.MOUSE_ENTERED:
  1545.         break;
  1546.         case MouseEvent.MOUSE_EXITED:
  1547.         if (!dragging) {
  1548.             setMouseTarget(null, e);
  1549.         }
  1550.         break;
  1551.         case MouseEvent.MOUSE_MOVED:
  1552.         lwOver = nativeContainer.getMouseEventTarget(e.getX(), e.getY(),false);
  1553.         setMouseTarget(lwOver, e);
  1554.         retargetMouseEvent(mouseEventTarget, id, e);
  1555.         break;
  1556.         }
  1557.         e.consume();
  1558.     }
  1559.  
  1560.     return e.isConsumed();
  1561.     }
  1562.  
  1563.     /**
  1564.      * Change the current target of mouse events.
  1565.      */
  1566.     private void setMouseTarget(Component target, MouseEvent e) {
  1567.     if (target != mouseEventTarget) {
  1568.         //System.out.println("setMouseTarget: " + target);
  1569.         mouseEventTarget = target;
  1570.     }
  1571.     }
  1572.  
  1573.     /*
  1574.      * Generates enter/exit events as mouse moves over lw components
  1575.      * @param targetOver    Target mouse is over (including native container)
  1576.      * @param e            Mouse event in native container
  1577.      */
  1578.     private void trackMouseEnterExit(Component targetOver, MouseEvent e) {
  1579.     Component    targetEnter = null;
  1580.     int        id = e.getID();
  1581.  
  1582.     if ( id != MouseEvent.MOUSE_EXITED &&
  1583.          id != MouseEvent.MOUSE_DRAGGED &&
  1584.          id != LWD_MOUSE_DRAGGED_OVER &&
  1585.          isMouseInNativeContainer == false ) {
  1586.         // any event but an exit or drag means we're in the native container
  1587.         isMouseInNativeContainer = true;
  1588.         startListeningForOtherDrags();
  1589.     } else if ( id == MouseEvent.MOUSE_EXITED ) {
  1590.         isMouseInNativeContainer = false;
  1591.         stopListeningForOtherDrags();
  1592.     }
  1593.  
  1594.     if (isMouseInNativeContainer) {
  1595.         targetEnter = targetOver;
  1596.     }
  1597.     //System.out.println("targetEnter = " + targetEnter);
  1598.     //System.out.println("targetLastEntered = " + targetLastEntered);
  1599.  
  1600.     if (targetLastEntered == targetEnter) {
  1601.         return;
  1602.     }
  1603.  
  1604.     retargetMouseEvent(targetLastEntered, MouseEvent.MOUSE_EXITED, e);
  1605.     if (id == MouseEvent.MOUSE_EXITED) {
  1606.         // consume native exit event if we generate one
  1607.         e.consume();
  1608.     }
  1609.  
  1610.     retargetMouseEvent(targetEnter, MouseEvent.MOUSE_ENTERED, e);
  1611.     if (id == MouseEvent.MOUSE_ENTERED) {
  1612.         // consume native enter event if we generate one
  1613.         e.consume();
  1614.     }
  1615.  
  1616.     //System.out.println("targetLastEntered: " + targetLastEntered);
  1617.     targetLastEntered = targetEnter;
  1618.     }
  1619.  
  1620.     private void startListeningForOtherDrags() {
  1621.     //System.out.println("Adding EventQueueListener");
  1622.     Toolkit.getEventQueue().addEventQueueListener(this);
  1623.     }
  1624.  
  1625.     private void stopListeningForOtherDrags() {
  1626.     //System.out.println("Removing EventQueueListener");
  1627.     Toolkit.getEventQueue().removeEventQueueListener(this);
  1628.     // removed any queued up dragged-over events
  1629.     Toolkit.getEventQueue().removeEvents(MouseEvent.class, LWD_MOUSE_DRAGGED_OVER);
  1630.     }
  1631.  
  1632.     /*
  1633.      * (Implementation of EventQueueListener)
  1634.      * Listen for drag events posted in other hw components so we can
  1635.      * track enter/exit regardless of where a drag originated
  1636.      */
  1637.     public void eventPosted(AWTEvent e) {
  1638.     boolean isForeignDrag = (e instanceof MouseEvent) &&
  1639.                 (e.id == MouseEvent.MOUSE_DRAGGED) &&
  1640.                 (e.getSource() != nativeContainer);
  1641.     
  1642.     if (!isForeignDrag) {
  1643.         // only interested in drags from other hw components
  1644.         return;
  1645.     }
  1646.  
  1647.     // execute trackMouseEnterExit on EventDispatchThread
  1648.     Toolkit.getEventQueue().postEvent(
  1649.         new TrackEnterExitEvent( nativeContainer, (MouseEvent)e )
  1650.     );
  1651.     }
  1652.  
  1653.     /*
  1654.      * ActiveEvent that calls trackMouseEnterExit as a result of a drag
  1655.      * originating in a 'foreign' hw container. Normally, we'd only be
  1656.      * able to track mouse events in our own hw container.
  1657.      */
  1658.     private class TrackEnterExitEvent extends AWTEvent implements ActiveEvent {
  1659.     MouseEvent    srcEvent;
  1660.     public TrackEnterExitEvent( Component trackSrc, MouseEvent e ) {
  1661.         super(trackSrc,0);
  1662.         srcEvent = e;
  1663.     }
  1664.  
  1665.     public void dispatch() {
  1666.         MouseEvent    me;
  1667.  
  1668.         synchronized (nativeContainer.getTreeLock()) {
  1669.         Component srcComponent = srcEvent.getComponent();
  1670.     
  1671.         // component may have disappeared since drag event posted
  1672.         // (i.e. Swing hierarchical menus)
  1673.         if ( !srcComponent.isShowing() ||
  1674.              !nativeContainer.isShowing() ) {
  1675.             return;
  1676.         }
  1677.     
  1678.         //
  1679.         // create an internal 'dragged-over' event indicating
  1680.         // we are being dragged over from another hw component
  1681.         //
  1682.         me = new MouseEvent(nativeContainer,
  1683.                    LWD_MOUSE_DRAGGED_OVER,
  1684.                    srcEvent.getWhen(),
  1685.                    srcEvent.getModifiers(),
  1686.                    srcEvent.getX(),
  1687.                    srcEvent.getY(),
  1688.                    srcEvent.getClickCount(),
  1689.                    srcEvent.isPopupTrigger());
  1690.         // translate coordinates to this native container
  1691.         Point    ptSrcOrigin = srcComponent.getLocationOnScreen();
  1692.         Point    ptDstOrigin = nativeContainer.getLocationOnScreen();
  1693.         me.translatePoint( ptSrcOrigin.x - ptDstOrigin.x, ptSrcOrigin.y - ptDstOrigin.y );
  1694.         }
  1695.         //System.out.println("Track event: " + me);
  1696.         // feed the 'dragged-over' event directly to the enter/exit
  1697.         // code (not a real event so don't pass it to dispatchEvent)
  1698.         Component targetOver = nativeContainer.getMouseEventTarget(me.getX(), me.getY(), true);
  1699.         trackMouseEnterExit(targetOver, me);
  1700.     }
  1701.     }
  1702.  
  1703.     /**
  1704.      * Sends a mouse event to the current mouse event recipient using
  1705.      * the given event (sent to the windowed host) as a srcEvent.  If
  1706.      * the mouse event target is still in the component tree, the 
  1707.      * coordinates of the event are translated to those of the target.
  1708.      * If the target has been removed, we don't bother to send the
  1709.      * message.
  1710.      */
  1711.     void retargetMouseEvent(Component target, int id, MouseEvent e) {
  1712.     if (target == null) {
  1713.         return; // mouse is over another hw component
  1714.     }
  1715.  
  1716.         int x = e.getX(), y = e.getY();
  1717.         Component component;
  1718.  
  1719.         for(component = target;
  1720.             component != null && component != nativeContainer;
  1721.             component = component.getParent()) {
  1722.             x -= component.x;
  1723.             y -= component.y;
  1724.         }
  1725.         if (component != null) {
  1726.             MouseEvent retargeted = new MouseEvent(target,
  1727.                                                    id, 
  1728.                                                    e.getWhen(), 
  1729.                                                    e.getModifiers(),
  1730.                                                    x, 
  1731.                                                    y, 
  1732.                                                    e.getClickCount(), 
  1733.                                                    e.isPopupTrigger());
  1734.  
  1735.         if (target == nativeContainer) {
  1736.         // avoid recursively calling LightweightDispatcher...
  1737.         ((Container)target).dispatchEventToSelf(retargeted);
  1738.         } else {
  1739.         target.dispatchEvent(retargeted);
  1740.         }
  1741.  
  1742.             // update cursor if needed.  This is done after the event has
  1743.             // been sent to the target so the target has a chance to change
  1744.             // the cursor after reacting to the event.
  1745.         Cursor c = target.getCursor();
  1746.         if (nativeContainer.getCursor() != c) {
  1747.         //System.out.println("Setting cursor to: " + c.getType());
  1748.         nativeContainer.setCursor(c);
  1749.         }
  1750.         }
  1751.     }
  1752.     
  1753.     // --- member variables -------------------------------
  1754.  
  1755.     /**
  1756.      * The windowed container that might be hosting events for 
  1757.      * lightweight components.
  1758.      */
  1759.     private Container nativeContainer;
  1760.  
  1761.     /**
  1762.      * The current lightweight component that has focus that is being
  1763.      * hosted by this container.  If this is a null reference then 
  1764.      * there is currently no focus on a lightweight component being 
  1765.      * hosted by this container 
  1766.      */
  1767.     private Component focus;
  1768.  
  1769.     /**
  1770.      * The current lightweight component being hosted by this windowed
  1771.      * component that has mouse events being forwarded to it.  If this
  1772.      * is null, there are currently no mouse events being forwarded to 
  1773.      * a lightweight component.
  1774.      */
  1775.     private transient Component mouseEventTarget;
  1776.  
  1777.     /**
  1778.      * The last component entered
  1779.      */
  1780.     private transient Component targetLastEntered;
  1781.  
  1782.     /**
  1783.      * Is the mouse over the native container
  1784.      */
  1785.     private transient boolean isMouseInNativeContainer = false;
  1786.  
  1787.     /**
  1788.      * Indicates if the mouse pointer is currently being dragged...
  1789.      * this is needed because we may receive exit events while dragging
  1790.      * and need to keep the current mouse target in this case.
  1791.      */
  1792.     private boolean dragging;
  1793.  
  1794.     /**
  1795.      * The cursor used by the native container that is hosting the
  1796.      * lightweight components.  Since the Cursor used by the lightweight
  1797.      * components overwrites the Cursor set in the native container
  1798.      * we need to stash the native cursor so we can restore it after
  1799.      * the lightweight components are done having their cursor shown.
  1800.      */
  1801.     private Cursor nativeCursor;
  1802.  
  1803.     /**
  1804.      * The event mask for contained lightweight components.  Lightweight
  1805.      * components need a windowed container to host window-related 
  1806.      * events.  This seperate mask indicates events that have been 
  1807.      * requested by contained lightweight components without effecting
  1808.      * the mask of the windowed component itself.
  1809.      */
  1810.     private long eventMask;
  1811.  
  1812.     /**
  1813.      * The kind of events routed to lightweight components from windowed
  1814.      * hosts.
  1815.      */
  1816.     private static final long PROXY_EVENT_MASK =
  1817.         AWTEvent.FOCUS_EVENT_MASK | 
  1818.         AWTEvent.KEY_EVENT_MASK |
  1819.         AWTEvent.MOUSE_EVENT_MASK | 
  1820.         AWTEvent.MOUSE_MOTION_EVENT_MASK;
  1821.  
  1822.     private static final long MOUSE_MASK = 
  1823.         AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK;
  1824. }
  1825.